#!/usr/bin/env python3
# _*_ coding:utf-8 _*_

from collections import OrderedDict
from django.shortcuts import render, redirect, HttpResponse
from django.urls import reverse
from django.forms import formset_factory

from rbac import models
from rbac.forms.Menu import MenuModelForm
from rbac.forms.Menu import SecondMenuModelForm
from rbac.forms.Menu import PermissionModelForm
from rbac.forms.Menu import MultiAddPermissionForm
from rbac.forms.Menu import MultiEditPermissionForm

from rbac.templatetags.urls import memory_reverse, memory_url
from rbac.init.routes import get_all_url_dict


def menu_list(request):
    """
    菜单列表
    :param request:
    :return:
    """
    menu_queryset = models.Menu.objects.all()
    menu_id = request.GET.get('mid')
    second_menu_id = request.GET.get('sid')
    menu_exists = models.Menu.objects.filter(id=menu_id).exists()
    if not menu_exists:
        menu_id = None
    if menu_id:
        second_menus = models.Permissions.objects.filter(menu_id=menu_id)
        menu_id = int(menu_id)
    else:
        second_menus = []
    second_menu_exists = models.Permissions.objects.filter(id=second_menu_id).exists()
    if not second_menu_exists:
        second_menu_id = None
    if second_menu_id:
        permissions = models.Permissions.objects.filter(pid_id=second_menu_id)
    else:
        permissions = []

    return render(request,
                  'rbac/menu_list.html',
                  {
                      'menus': menu_queryset,
                      'second_menus': second_menus,
                      'permissions': permissions,
                      'menu_id': menu_id,
                      'second_menu_id': second_menu_id,
                  })


def menu_add(request):
    if request.method == 'POST':
        forms = MenuModelForm(request.POST)
        if forms.is_valid():
            title = forms.cleaned_data['title']
            for_id = int(forms.cleaned_data['icon_id'])
            models.Menu.objects.create(title=title, icon_id=for_id)

            return redirect('rbac:menus')
    elif request.method == 'GET':
        forms = MenuModelForm()
    else:
        forms = MenuModelForm()

    return render(request, 'rbac/form_temp.html', {'forms': forms})


def menu_edit(request, pk):
    obj = models.Menu.objects.filter(id=pk).first()
    if not obj:
        return render(request, '404.html', {'error': '查看页面不存在！'})
    if request.method == 'GET':
        forms = MenuModelForm(instance=obj)
        return render(request, 'rbac/form_temp.html', {'forms': forms})
    forms = MenuModelForm(instance=obj, data=request.POST)
    if forms.is_valid():
        title = forms.cleaned_data['title']
        for_id = int(forms.cleaned_data['icon_id'])
        models.Menu.objects.filter(id=pk).update(title=title, icon_id=for_id)

        return redirect('rbac:menus')
    else:
        return render(request, 'rbac/form_temp.html', {'forms': forms})


def menu_del(request, pk):
    if request.method == 'POST':
        if pk == request.POST.get('pk') and request.POST.get('csrfmiddlewaretoken'):
            models.Menu.objects.filter(id=pk).delete()
            return HttpResponse('200')
    else:
        return render(request, '403.html')


def second_menu_add(request, menu_id):
    obj = models.Menu.objects.filter(id=menu_id).first()

    if request.method == 'GET':
        forms = SecondMenuModelForm(initial={'menu': obj})
        return render(request, 'rbac/form_temp.html', {'forms': forms})

    forms = SecondMenuModelForm(data=request.POST)
    if forms.is_valid():
        forms.save()
        return redirect(memory_reverse(request, 'rbac:menus'))

    return render(request, 'rbac/form_temp.html', {'forms': forms})


def second_menu_edit(request, pk):
    obj = models.Permissions.objects.filter(id=pk).first()
    if request.method == 'GET':
        forms = SecondMenuModelForm(instance=obj)
        return render(request, 'rbac/form_temp.html', {'forms': forms})

    forms = SecondMenuModelForm(data=request.POST, instance=obj)
    if forms.is_valid():
        forms.save()
        return redirect(memory_reverse(request, 'rbac:menus'))
    return render(request, 'rbac/form_temp.html', {'forms': forms})


def second_menu_del(request, pk):
    if request.method == 'POST':
        if pk == request.POST.get('pk') and request.POST.get('csrfmiddlewaretoken'):
            models.Permissions.objects.filter(id=pk).delete()
            return HttpResponse('200')
    else:
        return render(request, '403.html')


def permission_add(request, second_menu_id):
    if request.method == 'GET':
        forms = PermissionModelForm()
        return render(request, 'rbac/form_temp.html', {'forms': forms})

    forms = PermissionModelForm(data=request.POST)
    if forms.is_valid():
        second_menu_obj = models.Permissions.objects.filter(id=second_menu_id).first()
        if not second_menu_obj:
            return render(request, '404.html', {'error': '二级菜单不存在，请重新选择！'})
        forms.instance.pid = second_menu_obj
        forms.save()
        return redirect(memory_reverse(request, 'rbac:menus'))
    return render(request, 'rbac/form_temp.html', {'forms': forms})


def permission_edit(request, pk):
    obj = models.Permissions.objects.filter(id=pk).first()
    if request.method == 'GET':
        forms = PermissionModelForm(instance=obj)
        return render(request, 'rbac/form_temp.html', {'forms': forms})
    forms = PermissionModelForm(data=request.POST, instance=obj)
    if forms.is_valid():
        forms.save()
        return redirect(memory_reverse(request, 'rbac:menus'))
    return render(request, 'rbac/form_temp.html', {'forms': forms})


def permission_del(request, pk):
    if request.method == 'POST':
        if pk == request.POST.get('pk') and request.POST.get('csrfmiddlewaretoken'):
            models.Permissions.objects.filter(id=pk).delete()
            return HttpResponse('200')
    else:
        return render(request, '403.html')


def multi_permissions(request):
    post_type = request.GET.get('type')

    generate_formset_class = formset_factory(MultiAddPermissionForm, extra=0)
    update_formset_class = formset_factory(MultiEditPermissionForm, extra=0)

    generate_formset = None
    update_formset = None

    if request.method == 'POST' and post_type == 'generate':
        # 批量新增 权限url
        formset = generate_formset_class(data=request.POST)
        if formset.is_valid():
            obj_list = []
            post_row_list = formset.cleaned_data
            has_error = False

            for i in range(0, formset.total_form_count()):
                row_dict = post_row_list[i]
                try:
                    new_obj = models.Permissions(**row_dict)
                    new_obj.validate_unique()
                    obj_list.append(new_obj)
                except Exception as e:
                    formset.errors[i].update(e)
                    generate_formset = formset
                    has_error = True
            if not has_error:
                models.Permissions.objects.bulk_create(obj_list, batch_size=100)
        else:
            generate_formset = formset

    if request.method == 'POST' and post_type == 'update':
        formset = update_formset_class(data=request.POST)
        if formset.is_valid():
            post_row_list = formset.cleaned_data
            for i in range(0, formset.total_form_count()):
                row_dict = post_row_list[i]
                permission_id = row_dict.pop('id')
                try:
                    row_obj = models.Permissions.objects.filter(id=permission_id).first()
                    for k, v in row_dict.items():
                        setattr(row_obj, k, v)

                    row_obj.validate_unique()
                    row_obj.save()
                except Exception as e:
                    formset.errors[i].update(e)
                    update_formset = formset
        else:
            update_formset = formset

    all_url_dict = get_all_url_dict()
    route_name_set = set(all_url_dict.keys())
    permission_info = models.Permissions.objects.all().values('id', 'title', 'name', 'url', 'menu_id', 'pid_id')
    permission_dict = OrderedDict()
    permission_name_set = set()

    for row in permission_info:
        permission_dict[row['name']] = row
        permission_name_set.add(row['name'])

    for name, value in permission_dict.items():
        route_row_dict = all_url_dict.get(name)
        if not route_row_dict:
            continue
        if value['url'] != route_row_dict['url']:
            value['url'] = '路由与数据库中数据不一致！'

    # 增加的 url别名
    if not generate_formset:
        generate_name_list = route_name_set - permission_name_set
        generate_formset = generate_formset_class(
            initial=[row_dict for name, row_dict in all_url_dict.items() if name in generate_name_list]
        )
    # 删除的url 别名
    delete_name_list = permission_name_set - route_name_set
    delete_row_list = [
        row_dict for name, row_dict in permission_dict.items() if name in delete_name_list
    ]

    if not update_formset:
        update_name_list = permission_name_set & route_name_set
        update_formset = update_formset_class(
            initial=[row_dict for name, row_dict in permission_dict.items() if name in update_name_list]
        )

    return render(request, 'rbac/mutli_permissions.html',
                  {
                      'generate_formset': generate_formset,
                      'delete_row_list': delete_row_list,
                      'update_formset': update_formset,
                  })


def multi_permissions_del(request, pk):
    if request.method == 'POST':
        if pk == request.POST.get('pk') and request.POST.get('csrfmiddlewaretoken'):
            models.Permissions.objects.filter(id=pk).delete()
            return HttpResponse('200')
    else:
        return render(request, '403.html')


def distribute_permissions(request):
    # 获取角色权限
    role_id = request.GET.get('rid')
    if role_id:
        role_obj = models.Role.objects.filter(id=role_id).first()
        role_id = int(role_id)
        if not role_obj:
            role_id = None
            role_permissions_dict = {}
        else:
            role_permissions = role_obj.permissions.all()
            role_permissions_dict = {item.id: None for item in role_permissions}
    else:
        role_obj = None
        role_permissions_dict = {}
    # 修改角色权限
    if request.method == 'POST':
        permission_id_list = request.POST.getlist('permissions')
        if not role_obj:
            return render(request, '404.html', {'error': '请选择角色后，分配权限！'})
        role_obj.permissions.set(permission_id_list)
        url = reverse('rbac:distribute_permissions')
        return redirect('%s?rid=%s' % (url, role_id))
        # return redirect(memory_url(request, 'rbac:distribute_permissions'))

    all_role_list = models.Role.objects.all()
    all_menu_list = models.Menu.objects.values('id', 'title')
    all_menu_dict = {}
    for item in all_menu_list:
        item['children'] = []
        all_menu_dict[item['id']] = item

    all_second_menu_list = models.Permissions.objects.filter(menu__isnull=False).values('id', 'title', 'menu_id')

    all_second_menu_dict = {}

    for row in all_second_menu_list:
        row['children'] = []
        all_second_menu_dict[row['id']] = row
        all_menu_dict[row['menu_id']]['children'].append(row)

    all_permission_list = models.Permissions.objects.filter(menu__isnull=True).values('id', 'title', 'pid_id')

    for i in all_permission_list:
        pid = i['pid_id']
        if not pid:
            continue
        all_second_menu_dict[pid]['children'].append(i)

    return render(request, 'rbac/distribute_permission.html',
                  {
                      'all_role_list': all_role_list,
                      'role_id': role_id,
                      'all_menu_list': all_menu_list,
                      'role_permissions_dict': role_permissions_dict,

                  })
